#include "device.h"
#include <dlfcn.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "xf86drm.h"


CARD_CONFIG_INFO* card_config_info = NULL;
int card_info_nums = 0;

int open_device(const char *device)
{
    int fd = open(device, O_WRONLY);
    if (fd < 0)
    {
        printf("open device %s error", device);
        return -1;
    }
    return fd;
}

void close_device(int fd)
{
    if (fd > 0)
        close(fd);
}

void *open_lib_hander(const char *libname)
{
    static void *handle = NULL;
    if (handle != NULL)
        return handle;
    if ((handle = dlopen(libname, RTLD_LAZY)) == NULL)
    {
        printf("%s\n", dlerror());
        return NULL;
    }
    return handle;
}
void close_lib_hander(void *handle)
{
    if (handle)
        dlclose(handle);
}
int get_card_info(device_info_t *device_info)
{
    int max_device = 4;
    for (int i = 0; i < max_device; i++)
    {
        card_info_t *card_info = &device_info->card_info[i];
        char device_name[256] = {};
        sprintf(device_name, "/dev/dri/card%d", i);
        if (access(device_name, F_OK))
            continue;
        memcpy(card_info->device_name, device_name, 256);
        device_info->card_cnt++;
    }
    return 0;
}
int get_device_info(device_info_t *device_info)
{
    int fd=-1;
    get_card_info(device_info);
    for (int i = 0; i < device_info->card_cnt; i++)
    {
      card_info_t *card_info = &device_info->card_info[i];
      fd= open_device(card_info->device_name);
      drmDevicePtr device = NULL;
      drmGetDevice(fd, &device);
      card_info->device_id = device->deviceinfo.pci->device_id;
      card_info->vendor_id = device->deviceinfo.pci->vendor_id;
    //0 for discrete card, 1 for intergated card
        if (device->businfo.pci->bus > 0) {
          card_info->card_type = DISCRETE_CARD_TYPE;
        } else
          card_info->card_type = INTERGRATED_CARD_TYPE;
      drmFreeDevice(&device);
      close_device(fd);
    }
    return 0;
}
const char *get_vendor_name(int vendor_id)
{
    int index = get_cardinfoindex_byid(vendor_id);
    if (index > -1)
        return card_config_info[index].card_name;

    /*
    switch (vendor_id)
    {
    case 0x1002:
        return "AMD/ATI";
    case 0x8086:
        return "Intel";
    case 0x6766:
        return "Glenfly";
    case 0x10DE:
        return "NVIDIA";
    default:
        break;
    }
    */
    return "Unknown";
}


#define READ_LINE_LENGTH 2048

int load_card_config(const char* configFilePath)
{
    FILE * pfile;
    char buf[READ_LINE_LENGTH] = "";

    printf("\nload_card_config begin!\n");

    pfile = fopen(configFilePath, "r");

    if (pfile == NULL)
    {
        printf("open file %s failed!\n", configFilePath);
        return -1;
    }

    int bReadNum = 0;
    int line = 0;
    while (fgets(buf, READ_LINE_LENGTH, pfile))
    {
        if (';' == buf[0])
        {
            // printf("current ignore line %d is %s.\n", line, buf);
            continue;
        }

        // printf("current valid line %d is %s.\n", line, buf);

        if (!bReadNum)
        {
            if (0 != sscanf(buf, "card_num:%d", &card_info_nums))
            {
                printf("read card num is %d.\n", card_info_nums);
                card_config_info = (CARD_CONFIG_INFO*)malloc(sizeof(CARD_CONFIG_INFO) * card_info_nums);
                memset(card_config_info, 0, sizeof(CARD_CONFIG_INFO) * card_info_nums);
            }
            else
            {
                printf("read card num failed, line string %s.\n", buf);
                return -2;
            }
            bReadNum = 1;
        }
        else
        {
            char strplatform[32] = {0};
            if (5 == sscanf(buf, "%x %s %s %s %s",
                &card_config_info[line].card_id, card_config_info[line].card_name, strplatform,
                card_config_info[line].vaapi_path, card_config_info[line].vdpau_path))
            {
                printf("vendor_id:0x%x, vendor_name:%s, vaapi_path:%s, vdpau_path:%s, strplatform:%s.\n",
                    card_config_info[line].card_id, card_config_info[line].card_name,
                    card_config_info[line].vaapi_path, card_config_info[line].vdpau_path,
                    strplatform);
                #if defined __aarch64__
                    if (strncmp(strplatform, "aarch64", 7))
                    {
                        memset(card_config_info + line, 0, sizeof(CARD_CONFIG_INFO));
                        printf("current %d line config not a match aarch64 platform, ignore.\n", line);
                        continue;
                    }
                #else
                    if (strncmp(strplatform, "x86_64", 6))
                    {
                        memset(card_config_info + line, 0, sizeof(CARD_CONFIG_INFO));
                        printf("current %d line config not a match x86_64 platform, ignore.\n", line);
                        continue;
                    }
                #endif
            }
            else
            {
                printf("sscanf line buffer failed, please check line buffer: %s.\n", buf);
                return -3;
            }
            printf("load one config, valid line is %d!\n\n", line);
            line++;
        }
    }

    fclose(pfile);
    printf("load_card_config end, valid line is %d!\n\n", line);

    return 0;
}

int get_cardinfoindex_byid(int venderid)
{
    int index = -1;
    for (int i = 0; i < card_info_nums; i++)
    {
        // printf("%s, venderid=0x%x!\n", __func__, card_config_info[i].card_id);
        if (venderid == card_config_info[i].card_id)
        {
            index = i;
            return index;
        }
    }
    printf("get_cardinfoindex_byid failed, venderid=0x%x!\n", venderid);
    return index;
}
